package com.maxbill.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.maxbill.base.bean.*;
import lombok.extern.log4j.Log4j2;
import org.springframework.util.StringUtils;
import redis.clients.jedis.*;
import redis.clients.jedis.util.Slowlog;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

import static com.maxbill.fxui.util.CommonConstant.*;
import static com.maxbill.util.DataUtil.currentJedis;
import static com.maxbill.util.ItemUtil.*;
import static com.maxbill.util.StringUtil.*;

@Log4j2
public class RedisUtil {

    /**
     * 可用连接实例的最大数目，默认值为8；
     */
    private static final int MAX_TOTAL = 50;

    /**
     * pool最大空闲的jedis实例，默认值是8
     */
    private static final int MAX_IDLE = 10;

    /**
     * 等待可用连接的最大时间，单位毫秒，默认值为-1，表示永不超时
     */
    private static final int MAX_WAIT = 3000;

    /**
     * 超时时间
     */
    private static final int TIME_OUT = 3000;

    /**
     * 在borrow一个jedis实例时，是否提前进行validate操作；如果为true，则得到的jedis实例均是可用的；
     */
    private static final boolean TEST_ON_BORROW = true;

    private static final boolean TEST_ON_RETURN = true;

    /**
     * redis连接池
     */
    private static JedisPool jedisPool;

    /**
     * 资源锁
     */
    private static ReentrantLock lock = new ReentrantLock();

    /**
     * 初始化JedisPool
     */
    private static void initJedisPool(Connect connect) {
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxIdle(MAX_IDLE);
        poolConfig.setMaxTotal(MAX_TOTAL);
        poolConfig.setMaxWaitMillis(MAX_WAIT);
        poolConfig.setTestOnBorrow(TEST_ON_BORROW);
        poolConfig.setTestOnReturn(TEST_ON_RETURN);
        String host = connect.getRhost();
        int port = Integer.valueOf(connect.getRport());
        if (StringUtils.isEmpty(connect.getRpass())) {
            jedisPool = new JedisPool(poolConfig, host, port, TIME_OUT);
        } else {
            jedisPool = new JedisPool(poolConfig, host, port, TIME_OUT, connect.getRpass());
        }
    }

    /**
     * 释放当前Redis连接池
     */
    private static void freeJedisPool() {
        if (null != jedisPool && !jedisPool.isClosed()) {
            jedisPool.destroy();
        }
    }

    /**
     * 从JedisPool中获取Jedis
     */
    public static String openJedis(Connect connect) {
        try {
            //销毁旧的连接池
            freeJedisPool();
            //防止吃初始化时多线程竞争问题
            lock.lock();
            initJedisPool(connect);
            lock.unlock();
            currentJedis = jedisPool.getResource();
            return "";
        } catch (Exception e) {
            e.printStackTrace();
            String msg = e.getMessage();
            if (msg.contains(EXCEPTION_INFO_01)) {
                return MESSAGE_CONNECT_01;
            }
            if (msg.contains(EXCEPTION_INFO_02)) {
                return MESSAGE_CONNECT_02;
            }
            if (msg.contains(EXCEPTION_INFO_03)) {
                return MESSAGE_CONNECT_03;
            }
            if (msg.contains(EXCEPTION_INFO_04)) {
                return MESSAGE_CONNECT_04;
            }
            if (msg.contains(EXCEPTION_INFO_05)) {
                return MESSAGE_CONNECT_05;
            }
            if (msg.contains(EXCEPTION_INFO_06)) {
                return MESSAGE_CONNECT_06;
            }
            if (msg.contains(EXCEPTION_INFO_07)) {
                return MESSAGE_CONNECT_07;
            }
            if (msg.contains(EXCEPTION_INFO_08)) {
                return MESSAGE_CONNECT_08;
            }
            if (msg.contains(EXCEPTION_INFO_09)) {
                return MESSAGE_CONNECT_09;
            }
            return MESSAGE_CONNECT_10;
        }
    }

    /**
     * 释放Jedis连接
     */
    public static void closeJedis() {
        if (null != currentJedis) {
            currentJedis.close();
        }
    }

    private static Long getDbSize(int index) {
        currentJedis.select(index);
        return currentJedis.dbSize();
    }

    private static Long getDbTotal() {
        return Long.parseLong(getConf("databases").get(1));
    }


    /**
     * 获取REDIS信息
     */
    public static String getInfo(String info) {
        return currentJedis.info(isNull(info) ? "*" : info);
    }

    /**
     * 获取REDIS配置
     */
    private static List<String> getConf(String conf) {
        return currentJedis.configGet(isNull(conf) ? "*" : conf);
    }


    /**
     * 查询数据详情
     *
     * @param index 数据库索引
     * @param key   键名
     * @return 数据详情
     */
    public static DataNode getDataNode(int index, String key) {
        currentJedis.select(index);
        DataNode dataNode = new DataNode(key);
        dataNode.setTime(currentJedis.ttl(key).toString());
        String type = currentJedis.type(key);
        switch (type) {
            case "set":
                break;
            case "list":
                break;
            case "string":
                dataNode.setData(currentJedis.get(key));
                break;
            default:
        }
        dataNode.setSize(dataNode.getData().toString().getBytes().length + "");
        dataNode.setType(type);
        return dataNode;
    }


    /**
     * 查询服务信息列表
     *
     * @return 信息列表
     */
    public static List<InfoNode> getInfoList() {
        List<InfoNode> infoList = new ArrayList<>();
        Client client = currentJedis.getClient();
        client.info();
        String[] infoArray = client.getBulkReply().split("# ");
        for (String infoItem : infoArray) {
            if (!StringUtils.isEmpty(infoItem)) {
                infoList.addAll(getInfoList(infoItem));
            }
        }
        return infoList;
    }

    /**
     * 查询服务信息列表
     *
     * @return 信息列表
     */
    private static List<InfoNode> getInfoList(String infoItem) {
        List<InfoNode> infoList = new ArrayList<>();
        String[] infos = infoItem.split("\n");
        for (String info : infos) {
            if (info.contains(FLAG_COLON)) {
                InfoNode infoNode = new InfoNode();
                infoNode.setKey(getKeyString(FLAG_COLON, info).replace("\r", ""));
                infoNode.setVal(getValString(FLAG_COLON, info).replace("\r", ""));
                String json = FileUtil.readFileData(DATA_JSON_INFO);
                JSONObject jobj = JSON.parseObject(json);
                String txt = jobj.getString(infoNode.getKey());
                infoNode.setTxt(isNull(txt) ? "" : txt);
                infoList.add(infoNode);
            }
        }
        return infoList;
    }


    /**
     * 查询服务配置列表
     *
     * @return 配置列表
     */
    public static List<ConfNode> getConfList() {
        List<ConfNode> confList = new ArrayList<>();
        List<String> dataList = getConf("*");
        for (int i = 0; i < dataList.size(); i++) {
            if (i % 2 != 0) {
                ConfNode confNode = new ConfNode();
                String key = dataList.get(i - 1);
                confNode.setKey(key);
                String val = dataList.get(i);
                confNode.setVal(isNull(val) ? "" : val);
                String json = FileUtil.readFileData(DATA_JSON_CONF);
                JSONObject jobj = JSON.parseObject(json);
                String txt = jobj.getString(key);
                confNode.setTxt(isNull(txt) ? "" : txt);
                confList.add(confNode);
            }
        }
        return confList;
    }

    /**
     * 获取数据库列表
     *
     * @return 数据库列表
     */
    public static List<TreeNode> getDbList() {
        List<TreeNode> nodeList = new ArrayList<>();
        for (int i = 0; i < getDbTotal(); i++) {
            String name = "db" + i + "(" + getDbSize(i) + ")";
            nodeList.add(new TreeNode(name, i));
        }
        return nodeList;
    }

    /**
     * 查询KEY列表
     *
     * @param index 数据库索引
     * @param count 数据大小
     * @param param 查询参数
     * @return 数据列表
     */
    public static List<TreeNode> getDataList(int index, int count, String param) {
        long startTime = System.currentTimeMillis();
        currentJedis.select(index);
        List<String> dataList = new ArrayList<>();
        List<TreeNode> treeList = new ArrayList<>();
        param = isNull(param) ? "*" : param;
        //scan数据查询
        ScanParams scanParams = new ScanParams();
        scanParams.count(count);
        scanParams.match(param);
        while (true) {
            ScanResult<String> scanResult = currentJedis.scan("0", scanParams);
            List<String> elements = scanResult.getResult();
            if (elements != null && elements.size() > 0) {
                dataList.addAll(elements);
            }
            String cursor = scanResult.getCursor();
            if ("0".equals(cursor)) {
                break;
            }
        }
        long endTime = System.currentTimeMillis();
        log.info("getDataList查询耗时：{}", (endTime - startTime));
        //封装返回符合条件数据
        for (String key : dataList) {
            treeList.add(new TreeNode(key, index));
        }
        return treeList;
    }

    /**
     * 查询客户端连接信息
     *
     * @return 客户端信息
     */
    public static List<UserNode> getUserList() {
        List<UserNode> userList = new ArrayList<>();
        String usersInfo = currentJedis.clientList();
        if (StringUtils.isEmpty(usersInfo)) {
            return userList;
        }
        String[] users = usersInfo.split("\n");
        for (String user : users) {
            UserNode userNode = new UserNode();
            String[] items = user.split(" ");
            for (String item : items) {
                if (item.startsWith("id=")) {
                    userNode.setId(StringUtil.getValString(FLAG_EQUAL, item));
                }
                if (item.startsWith("addr=")) {
                    userNode.setHost(StringUtil.getValString(FLAG_EQUAL, item));
                }
                if (item.startsWith("age=")) {
                    userNode.setTime(StringUtil.getValString(FLAG_EQUAL, item));
                }
                if (item.startsWith("db=")) {
                    userNode.setDb(StringUtil.getValString(FLAG_EQUAL, item));
                }
            }
            userList.add(userNode);
        }
        return userList;
    }


    /**
     * 获取REDIS日志信息
     *
     * @return 日志信息
     */
    public static List<LogsNode> getLogsList() {
        List<Slowlog> slowList = currentJedis.slowlogGet(50);
        return LogsNode.copyToLogsNode(slowList);
    }

}
